

"""
GameController.py           
Author: Ryan Walters        
Date: 10-12-08             
Revision 3                  
                             
This class's responsibility 
has changed. It will have the duty
to implement the template method, and thereby
handle the initialization process and
get the game run loop started.

$Id: GameController.py 339 2008-10-17 03:57:13Z malerba89 $
"""


# imports
# need to get the Game, Logging, the UI, and Strategy
from Game import Game
from Logging import Logging
from GameView import *
from MakerMove import MakerMove
from BreakerMove import BreakerMove
from Tkinter import Menu
from WinFrame import WinFrame
from Command import Command
from MoveCommand import MoveCommand
from UndoCommand import UndoCommand
from NewGameCommand import NewGameCommand
from ToggleLoggingCommand import ToggleLoggingCommand
from CloseCommand import CloseCommand
from SpeedCommand import SpeedCommand
from MakerPlayer import MakerPlayer
from BreakerPlayer import BreakerPlayer
from InitializeOrder import InitializeOrder
from WinCommand import WinCommand
import sys

class GameController(InitializeOrder):
   
    # Things to handle include the following
    # A constructor, created when the App finishes initialization
    def __init__(self):
         # The following specify which variables are held in the gameController
        # A variable for the strategy of the codemaker
        self.Code_Maker_Player = None
        # A variable for the strategy of the codebreaker
        self.Code_Breaker_Player = None
        # A variable containing the current game
        self.game = None
        # A menu bar object
        self.menu = None
        # A variable representing the GUI
        self.GUI = InitializeGameView(self)
        # A variable representing the logger
        self.Log = None

        self.displayNewGameInput()

        self.GUI.Game_Run_Loop()
        
    #Builds the frame that handles getting data for new games from the user.
    #Also builds a closure to handle when the "New Game" button is pressed
    def displayNewGameInput(self):
        def handleNewGameFinished(waitTime,maker,breaker,logPath, makerIP, breakerIP):
            """docstring for handleNewGame"""
            self.newGame(waitTime,maker,breaker,logPath, makerIP, breakerIP)

        newGameFrame = NewGameFrame(self.GUI.getRootInputView(), handleNewGameFinished, width=300, height=100)
        self.GUI.set_input_view(newGameFrame)
    
    #Builds and returns the menu bar object
    def get_menu(self):
        self.menu = Menu(self.GUI.getRoot())
        #Make a list of players to send to the new game command
        playerList = [ self.Code_Maker_Player, self.Code_Breaker_Player ]
        self.newGameCommand = NewGameCommand(self, playerList)
        self.undoCommand = UndoCommand(self.game)
        self.closeCommand = CloseCommand(self.Log, playerList)
        self.toggleCommand = ToggleLoggingCommand(self.game, self.Log, self.closeCommand)
        self.speedCommand = SpeedCommand(playerList)
        self.winCommand = WinCommand(playerList)
        self.moveCommand = MoveCommand(self.game)
        
        # create a pulldown menu, and add it to the menu bar
        gamemenu = Menu(self.menu, tearoff=0)
        gamemenu.add_command(label="New game", command=self.newGameCommand.execute)
        gamemenu.add_command(label="Undo", command=self.undoCommand.execute)
        # These two need to be changed once text popups are finished
        gamemenu.add_command(label="Toggle Logging", command=self.toggleCommand.execute)
        gamemenu.add_command(label="Change Comp Speed", command=self.speedCommand.execute)
        # --------------------------------------------------------
        gamemenu.add_separator()
        gamemenu.add_command(label="Exit", command=self.closeCommand.execute)
        self.menu.add_cascade(label="Game", menu=gamemenu)
        return self.menu
    
    # A function to be invoked when creating a new game
    # wait time = the amount of time waiting before a move is submitted.  0 for human.
    # maker = int representing player type.  0 for Human, 1 for Computer
    # breaker = int representing player type.  0 for Human, 1 for Computer
    # log_Path = A string representing the path for logging.  None by default,
    # indicating nothing is turned on.  
    def newGame(self, waitTime, maker, breaker, log_Path, makerIP, breakerIP):
        self.game = None
        self.game = Game()
        self.GUI.getListView().reset_rows()
        self.game.register_observer(self.GUI.getListView())
        if waitTime is not None and waitTime > 30:
            waitTime = 30
        Maker_Player = MakerPlayer(self.game, makerIP, self.GUI, maker, waitTime)
        Breaker_Player = BreakerPlayer(self.game, breakerIP, self.GUI, breaker, waitTime)
        self.Code_Maker_Player = Maker_Player.getStrat()
        self.Code_Breaker_Player = Breaker_Player.getStrat()
        self.GUI.setMenu(self.get_menu())
        if log_Path is not None and log_Path is not "":
            self.Log = Logging(self.game, log_Path)

        # Due to dependency issues, we need to initialize the commands after the players are originally set.
        # This set of coding sets the commands to the players, one way or another.
        self.Code_Maker_Player.setCommands(self.undoCommand, self.winCommand, self.moveCommand,self.closeCommand, self.newGameCommand)
        self.Code_Breaker_Player.setCommands(self.undoCommand, self.winCommand, self.moveCommand,self.closeCommand, self.newGameCommand)
        self.setStartingCode(self.startGame)
                                 
    # A function for setting a Codemaker strategy
    def setMakerPlayer(self, player):
        self.Code_Maker_Player = MakerPlayer(self.game, makerIP, self.GUI, maker, waitTime)
        
    # A function for setting a Codebreaker strategy
    def setBreakerPlayer(self, player, waitTime):
        self.Code_Breaker_Player = BreakerPlayer(player, waitTime)
        
    # A function for starting a move from the Codebreaker strategy
    def getBreakerMove(self):
        functor = self.sendMove
        self.Code_Breaker_Player.getMove(functor, self.GUI)

    # A function for starting a move from the Codemaker strategy
    def getMakerResponse(self):
        functor = self.sendMove
        self.Code_Maker_Player.getMove(functor, self.GUI)

    # A function to set the strategy wait time
    def setWaitTime(self, time):
        if time is not None and time > 30:
            time = 30
        elif time is None:
            time = 0
        self.waitingTime = time
        self.Code_Breaker_Player.setWaitTime(time)

    # For the winning function
    def who_wins(self):
        return self.game.get_winner()

    #  Have the codemaker make its code
    def setStartingCode(self, startGame):
        """Tell the maker to make the code"""
        self.Code_Maker_Player.setStartingCode(startGame)

    #   Have the Codebreaker make the first move
    def startGame(self):
        """Begin the game"""
        self.Code_Breaker_Player.makeFirstMove(self.game)
            
#run program
if __name__ == '__main__':
	gc = GameController()
